package cn.slipi.admin.service.impl;

import cn.slipi.admin.common.dto.PageDTO;
import cn.slipi.admin.common.exception.base.BizException;
import cn.slipi.admin.common.utils.AppUtils;
import cn.slipi.admin.common.utils.StrUtils;
import cn.slipi.admin.common.utils.dozer.impl.ConvertBean;
import cn.slipi.admin.entity.CsmGrant;
import cn.slipi.admin.entity.CsmProject;
import cn.slipi.admin.dao.CsmProjectMapper;
import cn.slipi.admin.entity.PdrApi;
import cn.slipi.admin.service.CsmGrantService;
import cn.slipi.admin.service.CsmProjectService;
import cn.slipi.admin.service.PdrApiService;
import cn.slipi.admin.service.dto.in.consumer.GrantDTO;
import cn.slipi.admin.service.dto.in.consumer.KeyInfo;
import cn.slipi.admin.service.dto.in.consumer.ListDTO;
import cn.slipi.admin.service.dto.in.consumer.SaveDTO;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;


/**
 * <p>
 * 消费者表 服务实现类
 * </p>
 *
 * @author lee
 * @since 2020-12-01
 */
@Service
public class CsmProjectServiceImpl extends ServiceImpl<CsmProjectMapper, CsmProject> implements CsmProjectService {

    @Autowired
    private ConvertBean convertBean;

    @Autowired
    private PdrApiService pdrApiService;

    @Autowired
    private CsmGrantService csmGrantService;


    @Override
    public CsmProject getCsmById(Integer id) {
        QueryWrapper<CsmProject> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", id);
        queryWrapper.eq("status", 1);
        return this.baseMapper.selectOne(queryWrapper);
    }

    @Override
    public List<CsmProject> getCsmByIds(List<Integer> ids) {
        QueryWrapper<CsmProject> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("id", ids);
        queryWrapper.eq("status", 1);
        return this.baseMapper.selectList(queryWrapper);
    }

    @Override
    public PageDTO<CsmProject> getList(ListDTO dto) {
        IPage<CsmProject> page = new Page<>(dto.getPageNo(), dto.getPageSize());
        QueryWrapper<CsmProject> queryWrapper = new QueryWrapper<>();
        if (dto.getId() != null) {
            queryWrapper.eq("id", dto.getId());
        }
        if (StrUtils.isNotBlank(dto.getName())) {
            queryWrapper.like("name", dto.getName());
        }
        if (StrUtils.isNotBlank(dto.getDescription())) {
            queryWrapper.like("description", dto.getDescription());
        }
        if (StrUtils.isNotBlank(dto.getAppKey())) {
            queryWrapper.like("app_key", dto.getAppKey());
        }
        if (StrUtils.isNotBlank(dto.getAppSecret())) {
            queryWrapper.like("app_secret", dto.getAppSecret());
        }
        queryWrapper.orderByDesc("updated_at");
        queryWrapper.eq("status", 1);
        page = this.baseMapper.selectPage(page, queryWrapper);
        return PageDTO.of(page);
    }

    @Override
    public Integer add(SaveDTO saveDTO) {
        KeyInfo keyInfo = this.generator();
        CsmProject csmProject = this.getByNameOrAppKey(null, saveDTO.getName(), keyInfo.getAppKey());
        if (csmProject != null) {
            throw new BizException(10000, "record.key.found");
        }
        csmProject = this.convertBean.convert(saveDTO, CsmProject.class);
        csmProject.setAppKey(keyInfo.getAppKey());
        csmProject.setAppSecret(keyInfo.getAppSecret());
        csmProject.setRsaPublic(keyInfo.getRsaPublic());
        csmProject.setRsaPrivate(keyInfo.getRsaPrivate());
        this.baseMapper.insert(csmProject);
        return csmProject.getId();
    }

    @Override
    public List<CsmGrant> grant(GrantDTO grantDTO) {
        CsmProject csmProject = this.getById(grantDTO.getCsmId());
        if (csmProject == null) {
            throw new BizException(10000, "record.found.not");
        }
        List<PdrApi> pdrApiList = new ArrayList<>();
        if (grantDTO.getApiIdList().size() > 0) {
            pdrApiList = this.pdrApiService.getListByIds(grantDTO.getApiIdList());
        }

        List<CsmGrant> csmGrantList = new ArrayList<>();
        pdrApiList.forEach(pdrApi -> {
            CsmGrant csmGrant = new CsmGrant();
            csmGrant.setPdrId(pdrApi.getPdrProjectId());
            csmGrant.setPdrApiId(pdrApi.getId());
            csmGrant.setCsmId(grantDTO.getCsmId());
            csmGrant.setAppKey(csmProject.getAppKey());
            csmGrant.setAppSecret(csmProject.getAppSecret());
            csmGrant.setGrantParam(pdrApi.getGlobalGrantParam());
            csmGrant.setPdrApiCode(pdrApi.getCode());
            csmGrant.setPublishTime(0L);
            csmGrant.setPublishSnap("");
            csmGrant.setEnable(csmProject.getEnable());
            this.csmGrantService.getBaseMapper().insert(csmGrant);
            csmGrantList.add(csmGrant);
        });

        return csmGrantList;
    }

    @Override
    public CsmGrant unGrant(Integer grantId) {
        CsmGrant csmGrant = this.getGrantById(grantId);
        if (csmGrant == null) {
            throw new BizException(10000, "record.found.not");
        }
        this.csmGrantService.getBaseMapper().deleteById(grantId);
        return csmGrant;
    }

    @Override
    public List<CsmGrant> update(Integer id, SaveDTO saveDTO) {
        List<CsmGrant> csmGrantList = new ArrayList<>();
        CsmProject csmProject = this.getById(id);
        if (csmProject == null) {
            throw new BizException(10000, "record.found.not");
        }
        CsmProject csmProjectName = this.getByName(id, saveDTO.getName());
        if (csmProjectName != null) {
            throw new BizException(10000, "record.key.found");
        }
        if (!csmProject.getEnable().equals(saveDTO.getEnable())) {
            csmGrantList = this.csmGrantService.updateEnableByCsmId(id, saveDTO.getEnable());
        }
        this.convertBean.convertNotNull(saveDTO, csmProject, false, true);
        this.baseMapper.updateById(csmProject);
        return csmGrantList;
    }

    private CsmGrant getGrantById(Integer grantId) {
        QueryWrapper<CsmGrant> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", grantId);
        queryWrapper.eq("status", 1);
        return this.csmGrantService.getBaseMapper().selectOne(queryWrapper);
    }

    private CsmProject getById(Integer id) {
        QueryWrapper<CsmProject> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", id);
        queryWrapper.eq("status", 1);
        return this.baseMapper.selectOne(queryWrapper);
    }

    private CsmProject getByName(Integer id, String name) {
        QueryWrapper<CsmProject> queryWrapper = new QueryWrapper<>();
        if (id != null) {
            queryWrapper.ne("id", id);
        }
        queryWrapper.eq("name", name);
        queryWrapper.eq("status", 1);
        return this.baseMapper.selectOne(queryWrapper);
    }

    private CsmProject getByNameOrAppKey(Integer id, String name, String appKey) {
        QueryWrapper<CsmProject> queryWrapper = new QueryWrapper<>();
        if (id != null) {
            queryWrapper.ne("id", id);
        }
        queryWrapper.and(wrapper -> wrapper.eq("name", name).or().eq("app_key", appKey));
        queryWrapper.eq("status", 1);
        return this.baseMapper.selectOne(queryWrapper);
    }

    private KeyInfo generator() {
        KeyInfo keyInfo = new KeyInfo();
        String appKey = AppUtils.getAppKey();
        keyInfo.setAppKey(appKey);
        keyInfo.setAppSecret(AppUtils.getAppSecret(appKey));
        try {
            JSONObject rsa = AppUtils.initKey();
            keyInfo.setRsaPublic(rsa.getString("PUBLIC_KEY"));
            keyInfo.setRsaPrivate(rsa.getString("PRIVATE_KEY"));
        } catch (Exception ignored) {
            throw new BizException(10000, "rsa.generator.error");
        }
        return keyInfo;
    }
}
